/*
Copyright 2011, CSE Shareware Foundation
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, 
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, 
   this list of conditions and the following disclaimer in the documentation 
   and/or other materials provided with the distribution.
 * Neither the name of CSE Shareware Foundation nor the names of its contributors 
   may be used to endorse or promote products derived from this software without 
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "CseApi_.h"

#define CSE_FORMAT_BUFF            4096
#define STR_MARSH_LOOP_COUNT       8     // max get 8*4 byte to caculate hash

STATIC TInt32 MaskList[33] = { 0x0000,0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,
                               0x00FF,0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,
0x0000FFFF,0x0001FFFF,0x0003FFFF,0x0007FFFF,0x000FFFFF,0x001FFFFF,0x003FFFFF,0x007FFFFF,
0x00FFFFFF,0x01FFFFFF,0x03FFFFFF,0x07FFFFFF,0x0FFFFFFF,0x1FFFFFFF,0x3FFFFFFF,0x7FFFFFFF,
0xFFFFFFFF };

TInt32 MAKE_FLAG(TInt32 iFlag, TInt32 i, int iOffset, int n)
{
    ASSERT_TRUE(iOffset >= 0 && iOffset <= 31);
    ASSERT_TRUE(n >= 1 && (iOffset + n) <= 32);

    TInt32 iMask = MaskList[n] << iOffset;
    return (iFlag & (~iMask)) | ((i << iOffset) & iMask);
}

TInt32 READ_FLAG(TInt32 iFlag, int iOffset, int n)
{
    ASSERT_TRUE(iOffset >= 0 && iOffset <= 31);
    ASSERT_TRUE(n >= 1 && (iOffset + n) <= 32);
    return ((TUint32)iFlag >> iOffset) & MaskList[n];
}

#ifdef _UNICODE

TCharArray Cse_StrFromAnsi(const char *sour, int n)
{
    if (sour == NULL) n = 0;
    if (n == 0) return CseEmptyStr;

    int iLen = n;
    if (n < 0)  // get length of ansi string
    {
        iLen = mbstowcs(NULL,sour,0);
        if (iLen == -1)
            throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("maps multibyte-character string to wide-character string error"));
    }
    TCharArray ret(_T('\0'),iLen);

    // translate ANSI to Unicode
    mbstowcs(ret.addr(),sour,iLen);

    if (n < 0)
    {   // terminated by '\0'
        iLen = ret.len();
        if (iLen > 0 && ret[-1] == _T('\0'))
            ret.truncate(iLen-1);
    }
	return TCharArray(CUT_FROM,ret);
}

TCharArray Cse_StrFromUnicode(const TWchar *sour, int n)
{
    return TCharArray(sour,n);
}

#else

TCharArray Cse_StrFromAnsi(const char *sour, int n)
{
    return TCharArray(sour,n);
}

TCharArray Cse_StrFromUnicode(const TWchar *sour, int n)
{
    if (sour == NULL) n = 0;
    if (n == 0) return CseEmptyStr;

    int iLen = n;
    if (n < 0)  // get length of ansi string
    {
        iLen = wcstombs(NULL,sour,0);
        if (iLen == -1)
        {
            TCharArray sErr = TCharArray::format(_T("maps wide-character string to multibyte-character string error"));
            throw LOG_CSE_ERR(CSE_VALUE_ERR,sErr);
        }
    }
    TCharArray ret(_T('\0'),iLen);

    // translate Unicode to ANSI
    wcstombs(ret.addr(),sour,iLen);

    if (n < 0)
    {   // terminated by '\0'
        iLen = ret.len();
        if (iLen > 0 && ret[-1] == _T('\0'))
            ret.truncate(iLen-1);
    }
	return TCharArray(CUT_FROM,ret);
}

#endif

extern TXchar *__EmptyString;
extern const TCharArray& CseEmptyStr;

extern TCharArray *Cse_LastErrName;
extern TCharArray *Cse_LastErrDesc;

#ifndef CLOSE_REF_CHECK
  extern TInt32 gTotalCharArrayCount;
#endif

extern TCriticalSection *CseCharBuffLock;

class TCharBuffLocker
{
public:
    TCharBuffLocker(void)  { CseCharBuffLock->enter(); }
    ~TCharBuffLocker(void) { CseCharBuffLock->leave(); }
};

void LogErrNameAndDesc(const TCharArray& name, const TCharArray& desc)
{
    TCharBuffLocker lock;
    *Cse_LastErrName = name;
    *Cse_LastErrDesc = desc;
}

STATIC int StrNCompare(const TXchar* s1, int iLen1, const TXchar* s2, int iLen2)
{
    if (iLen1 == iLen2)
    {
        if (iLen1 == 0 || s1 == s2) return 0;
        else return memcmp(s1,s2,iLen1 * sizeof(TXchar));
    }
    else
    {
        int i;
        if (iLen1 < iLen2)
        {
            if (iLen1 == 0) return -1;

            i = memcmp(s1,s2,iLen1 * sizeof(TXchar));
            if (i == 0) return -1;
            else return i;
        }
        else
        {
            if (iLen2 == 0) return 1;

            i = memcmp(s1,s2,iLen2 * sizeof(TXchar));
            if (i == 0) return 1;
            else return i;
        }
    }
}

STATIC TXchar *NewCseCharBlock(TXchar ch, int n)
{
    if (n <= 0)
        return __EmptyString;
    else
    {
        int iLen = sizeof(TUint32[2]) + (n + 1) * sizeof(TXchar);
        TUint32 *pLen = (TUint32 *) new char[iLen];
        pLen[0] = n;
        pLen[1] = n;
        
        TXchar *ret = (TXchar *) &pLen[2];
        TXchar *pCh = ret;
        
        for (int i = 0; i < n; i++,pCh++) *pCh = ch;
        *pCh = _T('\0');
        
        return ret;
    }
}

STATIC TXchar *NewCseCharBlock(const TXchar *pSour, int iLen=-1, int iExt=0)
{
    ASSERT_TRUE(iExt >= 0);
    if (iLen == -1)
    {
        if (NULL == pSour)
            iLen = 0;
        else iLen = STRLEN(pSour);
    }
    else if (iLen < 0)
        throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("invalid TCharArray address"));
    
    int iNewLen = iLen + iExt;

    if (iNewLen == 0 || (pSour == NULL && iLen > 0))
        return __EmptyString;
    else
    {

        int iNew = sizeof(TUint32[2]) + (iNewLen + 1) * sizeof(TXchar);
        TUint32 *pLen = (TUint32 *) new char[iNew];
#ifdef _DEBUG
        if (pLen == NULL)
            PRINTF(_T("no memory or stack overflow\n"));
#endif
        pLen[0] = iNewLen;
        pLen[1] = iLen;
        TXchar *ret = (TXchar *) &pLen[2];

        // copy string context
        TXchar *pCh = ret;
        for (int i = 0; i < iLen; i++,pCh++,pSour++) *pCh = *pSour;
        *pCh = _T('\0');
        
        return ret;
    }
}

void TryFreeCharBlock(TXchar *pCh)
{
    if (pCh != __EmptyString)
    {
        char *SourAddr = (char *)pCh - sizeof(TUint32[2]);
        delete []SourAddr;
    }
}

TCharArray::TCharArray()
{
    m_data = __EmptyString;
#ifndef CLOSE_REF_CHECK
    gTotalCharArrayCount++;
#endif
}

TCharArray::TCharArray(int MagicNum, TCharArray& str)
{   // MagicNum = 20051206 means cut from
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));

    m_data = str.transfer(__EmptyString);
#ifndef CLOSE_REF_CHECK
    gTotalCharArrayCount++;
#endif
}

TCharArray::TCharArray(const TCharArray& s)
{
    TCharBuffLocker lock;
    m_data = NewCseCharBlock(s.m_data,s.len());
#ifndef CLOSE_REF_CHECK
    gTotalCharArrayCount++;
#endif
}

TCharArray::TCharArray(TXchar ch, int count)
{
    m_data = NewCseCharBlock(ch,count);
#ifndef CLOSE_REF_CHECK
    gTotalCharArrayCount++;
#endif
}

TCharArray::TCharArray(const TXchar* pSour, int iLen, int iExt)
{
    if (pSour == NULL && iExt == 0)
        m_data = __EmptyString;
    else
    {
        TCharBuffLocker lock;
        m_data = NewCseCharBlock(pSour,iLen,iExt);
    }
#ifndef CLOSE_REF_CHECK
    gTotalCharArrayCount++;
#endif
}

TCharArray::~TCharArray()
{
    TryFreeCharBlock(m_data);
#ifndef CLOSE_REF_CHECK
    gTotalCharArrayCount--;
#endif
}

TCharArray& TCharArray::joinEx(const TXchar* pSour, int iSourLen)
{
    if (iSourLen <= 0) return *this;  // no need join

    TUint32 *pLen = (TUint32 *) ((char *)m_data - sizeof(TUint32[2]));
    int iTargLen = pLen[1];
    int iTotal   = iTargLen + iSourLen;

    if ((int)pLen[0] >= iTotal)
    {   // have enough space
        TXchar *pTarg = m_data + iTargLen;
        for (int i = 0; i < iSourLen; i++,pTarg++,pSour++)
            *pTarg = *pSour;
        *pTarg = _T('\0');

        pLen[1] = iTotal;
    }
    else
    {   // add more space to hurry up continuous string adding
        int iPad = (iTotal + 1) / 2;

        // create enough space and join
        TCharArray ret(m_data,iTargLen,iSourLen + iPad);
        ret.tailJoin(pSour,iSourLen);

        // exchange the result and self
        ret.m_data = transfer(ret.m_data);
    }
    return *this;
}

TCharArray& TCharArray::join(const TCharArray& str, int index)
{
    TCharBuffLocker lock;

    int iSourLen = str.len();
    if (index < 0)
    {
        index = iSourLen + index;
        if (index < 0) index = 0;
    }

    return joinEx(str.m_data+index,iSourLen-index);
}

TCharArray& TCharArray::tailJoin(const TXchar* pSour, int iSourLen)
{
    TCharBuffLocker lock;
    int iSourLen_ = (iSourLen < 0)? ((pSour == NULL)? 0:STRLEN(pSour)): iSourLen;
    return joinEx(pSour,iSourLen_);
}

TCharArray& TCharArray::operator=(const TCharArray& str)
{
    TCharBuffLocker lock;
    
    int iSourLen = str.len();
    TUint32 *pLen = (TUint32 *) ((char *)m_data - sizeof(TUint32[2]));
    
    if ((int)pLen[0] >= iSourLen)
    {   // has enough space
        TXchar *pTarg = m_data;
        TXchar *pSour = str.m_data;
        for (int i = 0; i < iSourLen; i++,pTarg++,pSour++)
            *pTarg = *pSour;
        *pTarg = _T('\0');
        
        pLen[1] = iSourLen;
    }
    else
    {
        TryFreeCharBlock(m_data);
        m_data = NewCseCharBlock(str.m_data,iSourLen);
    }
    return *this;
}

TCharArray& TCharArray::operator=(const TXchar* pSour)
{
    TCharBuffLocker lock;

    int iSourLen = (pSour == NULL)? 0:STRLEN(pSour);
    TUint32 *pLen = (TUint32 *) ((char *)m_data - sizeof(TUint32[2]));

    if ((int)pLen[0] >= iSourLen)
    {   // has enough space
        TXchar *pTarg = m_data;
        for (int i = 0; i < iSourLen; i++,pTarg++,pSour++)
            *pTarg = *pSour;
        *pTarg = _T('\0');

        pLen[1] = iSourLen;
    }
    else
    {
        TryFreeCharBlock(m_data);
        m_data = NewCseCharBlock(pSour,iSourLen);
    }
    return *this;
}

TCharArray& TCharArray::operator=(TXchar ch)
{
    TCharBuffLocker lock;

    TUint32 *pLen = (TUint32 *) ((char *)m_data - sizeof(TUint32[2]));
    if (pLen[0] >= 1)
    {
        m_data[0] = ch;
        m_data[1] = _T('\0');
        pLen[1] = 1;
    }
    else
    {
        TryFreeCharBlock(m_data);
        m_data = NewCseCharBlock(ch,1);
    }
    return *this;
}

void TCharArray::operator+=(const TCharArray& str)
{
    TCharBuffLocker lock;
    joinEx(str.m_data,str.len());
}

void TCharArray::operator+=(const TXchar* pSour)
{
    tailJoin(pSour);
}

void TCharArray::operator+=(TXchar ch)
{
    tailJoin(&ch,1);
}

TCharArray TCharArray::multi(int n) const
{
    int iSourLen = len();
    int iTargLen = n * iSourLen;
    if (iTargLen <= 0) return CseEmptyStr;

    TCharArray ret;
    ret.m_data = NewCseCharBlock(_T('\0'),iTargLen);
    *(TUint32 *)((char *)ret.m_data - sizeof(TUint32)) = 0;

    TCharBuffLocker lock;
    for (int i = 0; i < n; i++)
        ret.joinEx(m_data,iSourLen);
    return TCharArray(CUT_FROM,ret);
}

TXchar& TCharArray::sub(int index) const
{
    TCharBuffLocker lock;

    int iLen = len();
    if (index < 0) index = iLen + index;

    CHECK_MSG(index >= 0 && index <= iLen,_T("access TCharArray out of range"));
    return m_data[index];
}

TXchar& TCharArray::operator[](int index) const
{
    return sub(index);
}

TCharArray::operator TXchar*() const
{
    return m_data;
}

TXchar *TCharArray::addr() const
{
    return m_data;
}

int TCharArray::len() const
{
    return CSE_ARRAY_LEN(m_data);
}

TBool TCharArray::isEmpty() const
{
    return len() <= 0;
}

TInt TCharArray::compare(const TCharArray& sOther) const
{
    TCharBuffLocker lock;
    return StrNCompare(m_data,len(),sOther.m_data,sOther.len());
}

TInt TCharArray::compare(const TXchar *pOther) const
{
    TCharBuffLocker lock;
    int iLen = (pOther == NULL)? 0:STRLEN(pOther);
    return StrNCompare(m_data,len(),pOther,iLen);
}

TCharArray TCharArray::slice(int index, int iLen) const
{
    TCharBuffLocker lock;

    int nLen = len();
    if (index < 0)
    {
        index = nLen + index;
        if (index < 0) index = 0;
    }

    if (index >= nLen || iLen == 0)
        return TCharArray();
    else
    {
        int iLeft = nLen - index;  // max left can copied
        if (iLen == -1 || iLen > iLeft) iLen = iLeft;
        return TCharArray(m_data + index,iLen);
    }
}

TXchar *TCharArray::transfer(TXchar *pOther)
{
    TXchar *ret = m_data;
    if (NULL == pOther)
        m_data = __EmptyString;
    else
    {
        TUint32 *pLen = (TUint32 *)((char *)pOther - sizeof(TUint32[2]));
        ASSERT_TRUE(pLen[0] >= pLen[1]);

        m_data = pOther;
    }
    return ret;
}

void TCharArray::exchange(TCharArray& other)
{
    TCharBuffLocker lock;
    other.transfer(transfer(other.addr()));
}

TBool TCharArray::copyFrom(const TXchar* pSour, int iLen, int iOff) const
{
    if (iOff + iLen > len()) return false;

    TXchar *pTarg = m_data + iOff;
    if (pTarg > pSour)
    {   // avoid backward overwrite
        pTarg += iLen - 1;
        pSour += iLen - 1;
        for (int i = iLen-1; i >= 0; i--,pTarg--,pSour--)
            *pTarg = *pSour;
    }
    else if (pTarg != pSour)
    {   // avoid forward overwrite
        for (int i = 0; i < iLen; i++,pTarg++,pSour++)
            *pTarg = *pSour;
    }
    // else, pTarg == pSour, // no need copy
    return true;
}

void TCharArray::insertEx(int iPos, const TXchar *pSour, int iLen)
{
    TUint32 *pLen = (TUint32 *)((char *)m_data - sizeof(TUint32[2]));
    int iTargLen = pLen[1];

    if (iPos == iTargLen)
    {
        joinEx(pSour,iLen);
        return;
    }
    
    int iTotal = iTargLen + iLen;

    if ((int)pLen[0] >= iTargLen + iLen)  // space is enough
    {
        pLen[1] = iTotal;
        copyFrom(m_data + iPos,iTargLen - iPos,iPos + iLen);
        copyFrom(pSour,iLen,iPos);
        m_data[iTotal] = _T('\0');
    }
    else
    {
        TCharArray ret(_T('\0'),iTotal);
        if (iPos > 0)
            ret.copyFrom(m_data,iPos,0);
        ret.copyFrom(pSour,iLen,iPos);
        ret.copyFrom(m_data + iPos,iTargLen - iPos,iPos + iLen);
        
        // exchange result and this
        ret.m_data = transfer(ret.m_data);
    }
}

TXchar TCharArray::append(TXchar ch)
{
    tailJoin(&ch,1);
    return ch;
}

TCharArray& TCharArray::add(TXchar ch, int *pIndex)
{
    TCharBuffLocker lock;
    if (pIndex != NULL) *pIndex = len();
    return joinEx(&ch,1);
}

const TIntObj& TCharArray::insert(int index, const TIntObj& obj)
{
    TCharBuffLocker lock;

    int nLen = len();
    if (index < 0)
    {
        index = index + nLen;
        if (index < 0) index = 0;
    }
    if (index > nLen) index = nLen;

    insertEx(index,(const TXchar*)&obj,1);
    return obj;
}

void TCharArray::insertSlice(int index, const TXchar *pSour, int iLen)
{
    TCharBuffLocker lock;
    int iLen_ = (iLen <= -1)? ((pSour == NULL)? 0:STRLEN(pSour)): iLen;
    if (iLen_ <= 0) return;
    
    int nLen = len();
    if (index < 0)
    {
        index = index + nLen;
        if (index < 0) index = 0;
    }
    if (index > nLen) index = nLen;
    
    insertEx(index,pSour,iLen_);
}

void TCharArray::remove(int index, int iLen)
{
    TCharBuffLocker lock;

    int nLen = len();
    if (index < 0)
    {
        index = index + nLen;
        if (index < 0) index = 0;
    }
    if (index >= nLen || iLen <= 0) return;

    int iLeft = nLen - index;     // max iLeft items can be deleted
    if (iLen > iLeft) iLen = iLeft;
    int iNewLen = nLen - iLen;
    
    if (iNewLen <= 0)
    {   // free old buffer
        TryFreeCharBlock(m_data);
        m_data = __EmptyString;
    }
    else
    {
        copyFrom(m_data + index + iLen,nLen - index - iLen,index);
        truncate(iNewLen);
    }
}

void TCharArray::clear()
{
    TCharBuffLocker lock;
    TryFreeCharBlock(m_data);
    m_data = __EmptyString;
}

int TCharArray::truncate(int iLen) const
{
    TCharBuffLocker lock;

    int nLen = len();
    if (iLen < 0) iLen += nLen;
    if (iLen < 0) iLen = 0;
    
    if (iLen < nLen)
    {
        m_data[iLen] = _T('\0');
        TUint32 *pNewLen = (TUint32 *)((char *)m_data - sizeof(TUint32));
        *pNewLen = iLen;

        return iLen;
    }
    else return nLen;
}

STATIC int FindSortIndex(const TXchar *m_data, int iHigh, TXchar ch)
{
    int iLow = 0;
    int index = -1;
    while (iLow <= iHigh)
    {
        int iHalf = (iLow + iHigh) >> 1;  // div 2
        TInt i = (TInt)m_data[iHalf] - (TInt)ch;

        if (i < 0)
            iLow = iHalf + 1;
        else if (i == 0)
        {
            index = iHalf;
            break;
        }
        else iHigh = iHalf - 1;
    }
    if (index == -1) index = iLow;

    return index;
}

int TCharArray::sortAdd(TXchar ch)
{
    TCharBuffLocker lock;

    int index = FindSortIndex(m_data,len()-1,ch);
    insertEx(index,&ch,1);
    return index;
}

void TCharArray::sort() const
{
    TCharBuffLocker lock;

    int iCount;
    int iLen = len();
    if (iLen <= 1) return; // no need to sort

    // first make empty-string-copy and sort-add every item
    TCharArray sTmp(NULL,0,iLen);
    TXchar *sSour = addr();
    TXchar *sTarg = sTmp.addr();
    for (iCount = 0; iCount < iLen; iCount++,sSour++)
        sTmp.insertEx(FindSortIndex(sTarg,iCount-1,*sSour),sSour,1);

    // then copy back context
    sSour = sTarg; sTarg = addr(); sSour = sTmp.addr();
    for (iCount = 0; iCount < iLen; iCount++,sSour++,sTarg++)
        *sTarg = *sSour;
}

TCharArray TCharArray::vformat(const TXchar *frmt, va_list ArgPtr)
{
    TXchar buff[CSE_FORMAT_BUFF];
    int iLen = VSPRINTF(buff,frmt,ArgPtr);
    ASSERT_MSG(iLen < CSE_FORMAT_BUFF,_T("out of print buffer range"));

    return TCharArray(buff,iLen);
}

TCharArray TCharArray::format(const TXchar *frmt, ...)
{
    va_list ArgPtr;
    va_start(ArgPtr,frmt);

    TXchar buff[CSE_FORMAT_BUFF];
    int iLen = VSPRINTF(buff,frmt,ArgPtr);
    va_end(ArgPtr);
    ASSERT_MSG(iLen < CSE_FORMAT_BUFF,_T("out of print buffer range"));

    return TCharArray(buff,iLen);
}

void TCharArray::resize(int iSize)
{
    TCharBuffLocker lock;

    TUint32 *pLen = (TUint32 *)((char *)m_data - sizeof(TUint32[2]));
    int iCurrSize = pLen[0];

    if (iCurrSize >= iSize)  // space is enough
        pLen[1] = iSize;
    else
    {   // create enlarged new string
        TCharArray ret(m_data,pLen[1],iSize - iCurrSize);
        ret.m_data = transfer(ret.m_data); // exchange
        
        TUint32 *pNewLen = (TUint32 *)((char *)m_data - sizeof(TUint32));
        *pNewLen = iSize;
    }
    m_data[iSize] = _T('\0');
}

TUint32 TCharArray::hash() const
{
    TCharBuffLocker lock;

    TUint32 ret;
    TUint32 size = len();
    int iMaxLoop = 28;

    if (size <= 5)
    {
        ret = (_T('#') ^ m_data[0]) << 12;
        int iLoop = 0;
        for (int iCount = size-1; iCount >= 1; iCount--)
        {
            ret = ret ^ ((_T('0') ^ m_data[iCount]) << iLoop);
            iLoop += 4; // #1234, char4(bit0~3) char3(bit4~7) char2(bit8~11) char1(12~15)
            if (iLoop > iMaxLoop) iLoop = 0;
        }
    }
    else
    {
        size = size * sizeof(TXchar);     // TXchar maybe _UNICODE
        int iLoop = size / sizeof(TUint32);
        if (iLoop > STR_MARSH_LOOP_COUNT) // max use STR_MARSH_LOOP_COUNT * 4 bytes
            iLoop = STR_MARSH_LOOP_COUNT;

        ret = size;
        TUint32 *p = (TUint32 *)m_data;
        for (int iCount = 0; iCount < iLoop; iCount++, p++)
            ret ^= *p;
    }

    return ret;
}

TCharArray TCharArray::str(TXchar pre) const
{
    TCharBuffLocker lock;

    int iLen = len();
    TCharArray ret = pre;

    if (0 == iLen)
    {
        ret += pre;
        return ret;
    }

    TBool inEscape = false;
    for (int iCount=0; iCount < iLen; iCount++)
    {
        TXchar ch = m_data[iCount];

        if (inEscape)
        {
            ret += ch;
            inEscape = false;
        }
        else if (ch == _T('\\'))
        {
            inEscape = true;
            ret += _T('\\');
            ret += ch;
        }
        else if (ch == pre)
        {
            ret += _T('\\');
            ret += ch;
        }
        else if ( ch == _T('\t') )
            ret += _T("\\t");
        else if ( ch == _T('\n') )
            ret += _T("\\n");
        else if ( ch == _T('\v') )
            ret += _T("\\v");
        else if ( ch == _T('\f') )
            ret += _T("\\f");
        else if ( ch == _T('\r') )
            ret += _T("\\r");
        else if ( ch == _T('\0') )
            ret += _T("\\0");
        else
        {
#ifdef _UNICODE
            ret += ch;
#else
            if (ch < ' ' || ch >= 127)
                ret += format(_T("\\x%.2x"),(unsigned char)ch);
            else ret += ch;
#endif
        }
    }
    ret += pre;

    return TCharArray(CUT_FROM,ret);
}

TBool TCharArray::toInt(TInt& ret) const
{
    ret = 0;
    TInt64 iTmp = 0;                 // "%I64i" "%lli"
    if (SSCANF(m_data,_T("%") CseLongLongFmtSpec _T("i"),&iTmp) != 0)
    {
        ret = (TInt)iTmp;
        return true;
    }
    else return false;
}

TBool TCharArray::toWint(TInt64& ret) const
{
    ret = 0;                         // "%I64i" "%lli"
    return SSCANF(m_data,_T("%") CseLongLongFmtSpec _T("i"),&ret) != 0;
}

TBool TCharArray::toDouble(TDouble& ret) const
{
    TXchar *RetPtr = m_data;
    ret = STRTOD(m_data,&RetPtr);
    return RetPtr > m_data;
}

const TCharArray& TCharArray::upper() const
{
    TCharBuffLocker lock;

    int iLen = len();
    if (iLen == 0) return *this; // no need uppercase
    
    TXchar *pTarg = m_data;
    TXchar offset = _T('a') - _T('A');
    for (int i = 0; i < iLen; i++,pTarg++)
    {
        TXchar ch = *pTarg;
        if (ch >= _T('a') && ch <= _T('z'))
            *pTarg = ch - offset;
    }
    return *this;
}

const TCharArray& TCharArray::lower() const
{
    TCharBuffLocker lock;

    int iLen = len();
    if (iLen <= 0) return *this; // no need lowercase

    TXchar *pTarg = m_data;
    TXchar offset = _T('a') - _T('A');
    for (int i = 0; i < iLen; i++,pTarg++)
    {
        TXchar ch = *pTarg;
        if (ch >= _T('A') && ch <= _T('Z'))
            *pTarg = ch + offset;
    }
    return *this;
}

TCharArray TCharArray::toUpper() const
{
    TCharArray sRet(*this);
    sRet.upper();
    return TCharArray(CUT_FROM,sRet);
}

TCharArray TCharArray::toLower() const
{
    TCharArray sRet(*this);
    sRet.lower();
    return TCharArray(CUT_FROM,sRet);
}

int TCharArray::trim() const
{
    TCharBuffLocker lock;
    
    int iLen = len();
    if (iLen == 0) return iLen; // no need trim

    // first, trim right
    int i;
    int iCount = 0;
    for (i = iLen-1; i >= 0; i--)
    {
        TXchar ch = m_data[i];
        if ( ch == _T(' ') || ch == _T('\t') || ch == _T('\n') ||
             ch == _T('\r') || ch == _T('\v') || ch == _T('\f') )
            iCount++;
        else break;
    }
    if (iCount > 0)
    {
        iLen -= iCount;
        truncate(iLen);
    }

    // then, trim left
    iCount = 0;
    for (i = 0; i < iLen; i++)
    {
        TXchar ch = m_data[i];
        if ( ch == _T(' ') || ch == _T('\t') || ch == _T('\n') ||
             ch == _T('\r') || ch == _T('\v') || ch == _T('\f') )
            iCount++;
        else break;
    }
    if (iCount > 0)
    {
        iLen -= iCount;
        copyFrom(m_data+iCount,iLen,0);
        truncate(iLen);
    }

    return iLen;
}

int TCharArray::trimLeft() const
{
    TCharBuffLocker lock;

    int iLen = len();
    if (iLen <= 0) return iLen; // no need trim

    int iCount = 0;
    for (int i = 0; i < iLen; i++)
    {
        TXchar ch = m_data[i];
        if ( ch == _T(' ') || ch == _T('\t') || ch == _T('\n') ||
             ch == _T('\r') || ch == _T('\v') || ch == _T('\f') )
            iCount++;
        else break;
    }
    if (iCount > 0)
    {
        iLen -= iCount;
        copyFrom(m_data + iCount,iLen,0);
        truncate(iLen);
    }

    return iLen;
}

int TCharArray::trimRight() const
{
    TCharBuffLocker lock;

    int iLen = len();
    if (iLen <= 0) return iLen; // no need trim

    int iCount = 0;
    for (int i = iLen-1; i >= 0; i--)
    {
        TXchar ch = m_data[i];
        if ( ch == _T(' ') || ch == _T('\t') || ch == _T('\n') ||
             ch == _T('\r') || ch == _T('\v') || ch == _T('\f') )
            iCount++;
        else break;
    }
    if (iCount > 0)
    {
        iLen -= iCount;
        truncate(iLen);
    }
    
    return iLen;
}

int TCharArray::find(TXchar ch, int from) const
{
    TCharBuffLocker lock;

    int iLen = len();
    if (from >= iLen) return -1;

    if (from < 0) from = iLen + from;
    if (from < 0) from = 0;

    TXchar *pChar = m_data + from;
    for (int i = from; i < iLen; i++, pChar++)
    {
        if (*pChar == ch)
            return i;
    }
    return -1;
}

int TCharArray::find(const TXchar *pSub, int from) const
{
    TCharBuffLocker lock;

    int iLen = len();
    
    if (from < 0) from += iLen;
    if (from >= iLen) return -1;
    if (from < 0) from = 0;

    TXchar *sTarg = m_data + from;
    TXchar *s = STRSTR(sTarg,pSub);
    if (s != NULL)
        return s - m_data;
    else return -1;
}

TBool TCharArray::enumItem(void*& pIter, TXchar *pRet) const
{
    TCharBuffLocker lock;

    if (pIter == NULL)  // start enumlate
        pIter = m_data;
    else pIter = (TXchar *)pIter + 1;

    // maybe the dict has resize
    if ((TXchar *)pIter < m_data) return false;
    TXchar *pEnd = m_data + CSE_ARRAY_LEN(m_data);
    if ((TXchar *)pIter < pEnd)
    {
        if (pRet != NULL) *pRet = *(TXchar *)pIter;
        return true;
    }
    else return false;
}

int TCharArray::count(const TXchar* pSub, int iStart, int iEnd) const
{
    if (pSub == NULL) return 0;
    
    TCharBuffLocker lock;
    int iSeg = STRLEN(pSub);
    if (iSeg == 0) return 0;

    int iLen = len();
    
    if (iStart < 0) iStart += iLen;
    if (iStart >= iLen) return 0;
    if (iStart < 0) iStart = 0;

    if (iEnd < 0)
    {
        iEnd += iLen;
        if (iEnd < 0) return 0;
    }
    else if (iEnd == 0)
        iEnd = iLen;
    if (iEnd > iLen) iEnd = iLen;

    int iNum = 0;
    TXchar *sTarg = m_data + iStart;
    TXchar *sEnd  = m_data + iEnd;
    TXchar *s; 
    while ((s = STRSTR(sTarg,pSub)) != NULL)
    {
        sTarg = s + iSeg;
        if (sTarg < sEnd)
            iNum++;
        else if (sTarg == sEnd)
        {
            iNum++;
            break;
        }
        else break;
    }

    return iNum;
}

TCharArray& TCharArray::align(int iWidth, TXchar fillChar)
{
    TCharBuffLocker lock;

    TUint32 *pLen = (TUint32 *)((char *)m_data - sizeof(TUint32[2]));
    int iOldLen = pLen[1];
    if (iWidth <= iOldLen)
        return *this;

    if ((int) pLen[0] >= iWidth)  // space is enough
        pLen[1] = iWidth;
    else
    {   // create enlarged new string
        TCharArray ret(m_data,iOldLen,iWidth - iOldLen);
        ret.m_data = transfer(ret.m_data); // exchange
        
        TUint32 *pNewLen = (TUint32 *)((char *)m_data - sizeof(TUint32));
        *pNewLen = iWidth;
    }
    m_data[iWidth] = _T('\0');

    int iPos = (iWidth - iOldLen) / 2;
    int i;
    for (i = iWidth - 1; i >= iOldLen + iPos; i--)
        m_data[i] = fillChar;

    if (iPos)
    {
        for (i = iOldLen + iPos - 1; i >= iPos; i--)
            m_data[i] = m_data[i-iPos];
        for (i = iPos - 1; i >= 0; i--)
            m_data[i] = fillChar;
    }

    return *this;
}

TCharArray& TCharArray::alignLeft(int iWidth, TXchar fillChar)
{
    TCharBuffLocker lock;

    TUint32 *pLen = (TUint32 *)((char *)m_data - sizeof(TUint32[2]));
    int iOldLen = pLen[1];
    if (iWidth <= iOldLen)
        return *this;

    if ((int) pLen[0] >= iWidth)  // space is enough
        pLen[1] = iWidth;
    else
    {   // create enlarged new string
        TCharArray ret(m_data,iOldLen,iWidth - iOldLen);
        ret.m_data = transfer(ret.m_data); // exchange
        
        TUint32 *pNewLen = (TUint32 *)((char *)m_data - sizeof(TUint32));
        *pNewLen = iWidth;
    }
    m_data[iWidth] = _T('\0');

    for (int i = iWidth - 1; i >= iOldLen; i--)
        m_data[i] = fillChar;

    return *this;
}

TCharArray& TCharArray::alignRight(int iWidth, TXchar fillChar)
{
    TCharBuffLocker lock;

    TUint32 *pLen = (TUint32 *)((char *)m_data - sizeof(TUint32[2]));
    int iOldLen = pLen[1];
    if (iWidth <= iOldLen)
        return *this;

    if ((int) pLen[0] >= iWidth)  // space is enough
        pLen[1] = iWidth;
    else
    {   // create enlarged new string
        TCharArray ret(m_data,iOldLen,iWidth - iOldLen);
        ret.m_data = transfer(ret.m_data); // exchange
        
        TUint32 *pNewLen = (TUint32 *)((char *)m_data - sizeof(TUint32));
        *pNewLen = iWidth;
    }
    m_data[iWidth] = _T('\0');

    int iPos = iWidth - iOldLen;
    int i;
    for (i = iWidth - 1; i >= iPos; i--)
        m_data[i] = m_data[i-iPos];
    for (i = iPos - 1; i >= 0; i--)
        m_data[i] = fillChar;

    return *this;
}

TCharArray& TCharArray::replace(const TXchar *sSub,const TXchar *sNew,int count)
{
    if (sSub == NULL || count == 0) return *this;

    TCharBuffLocker lock;
    int SubLen = STRLEN(sSub);
    if (SubLen == 0) return *this;

    TUint32 *pLen = (TUint32 *)((char *)m_data - sizeof(TUint32[2]));
    int iOldLen = pLen[1];
    TIntArray founds;

    TXchar *sTarg = m_data;
    TXchar *sEnd = m_data + iOldLen;
    TXchar *s;
    while ((s = STRSTR(sTarg,sSub)) != NULL)
    {
        sTarg = s + SubLen;
        if (sTarg < sEnd)
            founds.append((TInt) (s - m_data));
        else if (sTarg == sEnd)
        {
            founds.append((TInt) (s - m_data));
            break;
        }
        else break;

        if (count > 0 && founds.len() >= count) break; // max replace 'count' sSub
    }

    int FoundNum = founds.len();
    if (FoundNum)
    {
        int NewLen = STRLEN(sNew);
        if (NewLen == SubLen)
        {
            for (int i = FoundNum - 1; i >= 0; i--)
                STRNCPY(m_data + founds[i],sNew,NewLen);
        }

        else if (NewLen > SubLen)
        {   // enlarge string
            int iWidth = iOldLen + (NewLen - SubLen) * FoundNum;

            if ((int) pLen[0] >= iWidth)  // space is enough
                pLen[1] = iWidth;
            else
            {   // create enlarged new string
                TCharArray ret(m_data,iOldLen,iWidth - iOldLen);
                ret.m_data = transfer(ret.m_data); // exchange
        
                TUint32 *pNewLen = (TUint32 *)((char *)m_data - sizeof(TUint32));
                *pNewLen = iWidth;
            }
            m_data[iWidth] = _T('\0');

            int iOldLast = iOldLen-1;
            int iNewLast = iWidth-1;
            for (int i = FoundNum - 1; i >= 0; i--)
            {
                int iPos = founds[i] + SubLen;
                while (iOldLast >= iPos)
                {
                    m_data[iNewLast] = m_data[iOldLast];
                    iOldLast--; iNewLast--;
                }

                for (int i2 = NewLen-1; i2 >= 0; i2--,iNewLast--)
                    m_data[iNewLast] = sNew[i2];
                iOldLast -= SubLen;
            }

            ASSERT_TRUE(iNewLast == iOldLast);
        }

        else // NewLen < SubLen
        {
            int iWidth = iOldLen - (SubLen - NewLen) * FoundNum;
            pLen[1] = iWidth;

            int iOldLast = 0;
            int iNewLast = 0;
            for (int i = 0; i < FoundNum; i++)
            {
                int iPos = founds[i];
                if (i == 0)
                {
                    iNewLast = iPos;
                    iOldLast = iPos;
                }
                else
                {
                    while (iOldLast < iPos)
                    {
                        m_data[iNewLast] = m_data[iOldLast];
                        iOldLast++; iNewLast++;
                    }
                }

                for (int i2 = 0; i2 < NewLen; i2++,iNewLast++)
                    m_data[iNewLast] = sNew[i2];
                iOldLast += SubLen;
            }

            while (iOldLast < iOldLen)
            {
                m_data[iNewLast] = m_data[iOldLast];
                iOldLast++; iNewLast++;
            }

            ASSERT_TRUE(iNewLast == iWidth);
            m_data[iWidth] = _T('\0');
        }
    }

    return *this;
}

TObjArray TCharArray::split(const TXchar* sSep, int count, TBool headTail) const
{
    TObjArray bRet;
    if (count == 0) return bRet;

    TCharBuffLocker lock;
    int iLen = len();
    if (iLen == 0) return bRet;
    TXchar *sEnd  = m_data + iLen;

    if (sSep == NULL || *sSep == _T('\0'))
    {   // split with white space: ( space    \t -- \r)
        TXchar *sTarg = m_data;
        TXchar *sLast = m_data;

        TXchar ch;
        TBool LastIsWhite = false;
        while ((ch = *sTarg) != 0)   // end at '\0'
        {   // can add one at least, ASSERT(count < 0 || count >= 1);
            sTarg++;

            if ( ch == _T(' ') || (ch >= _T('\t') && ch <= _T('\r')) )
            {   // current is white space
                if (! LastIsWhite)
                {
                    int iOneLen = (int) (sTarg - sLast - 1);
                    if (iOneLen)
                    {
                        TCharArray sTmp = TCharArray(sLast,iOneLen);
                        bRet.append(TCseObj(CUT_FROM,sTmp));
                    }
                    else if (headTail && sLast == m_data)
                    {
                        bRet.append(CseEmptyStr);  // head string
                    }

                    LastIsWhite = true;
                }
                // else, LastIsWhite = true;
                sLast = sTarg;
            }
            else
            {   // current is not white space
                if (LastIsWhite)
                {
                    sLast = sTarg - 1;
                    LastIsWhite = false;
                }
                // else, LastIsWhite = false
            }

            if (sTarg >= sEnd)
            {
                if (sLast >= sEnd)
                {
                    if (LastIsWhite && headTail && (count < 0 || bRet.len() < count))
                        bRet.append(CseEmptyStr);  // tail string
                    sLast = NULL;
                }
                else if (count > 0 && bRet.len() >= count)
                    sLast = NULL;
                break;
            }
            else if (count > 0 && bRet.len() >= count)
            {
                sLast = NULL;
                break;
            }
        }

        if (sLast != NULL && sLast != m_data)
        {   // try add left words
            int iOneLen = (int) (sEnd - sLast);
            if (iOneLen)
            {
                TCharArray sTmp = TCharArray(sLast,iOneLen);
                bRet.append(TCseObj(CUT_FROM,sTmp));
            }
        }
    }

    else
    {
        int iSeg = STRLEN(sSep);
        if (iSeg == 0) return bRet;
    
        TXchar *sTarg = m_data;
        TXchar *sNext = NULL;
        TXchar *s; 
        while ((s = STRSTR(sTarg,sSep)) != NULL)
        {   // can add one at least, ASSERT(count < 0 || count >= 1);
            sNext = s + iSeg;

            int iOneLen = (int) (s - sTarg);
            if (iOneLen)
            {
                TCharArray sTmp = TCharArray(sTarg,iOneLen);
                bRet.append(TCseObj(CUT_FROM,sTmp));
            }
            else if (headTail)  // iOneLen == 0
            {
                bRet.append(CseEmptyStr);      // head string, or continous sSep
            }

            if (sNext >= sEnd)
            {
                if (headTail && (count < 0 || bRet.len() < count))
                    bRet.append(CseEmptyStr);  // tail string
                sNext = NULL;
                break;
            }
            else sTarg = sNext;
            
            if (count > 0 && bRet.len() >= count)
            {
                sNext = NULL;
                break;
            }
        }

        if (sNext != NULL)
        {   // try add left words
            ASSERT_TRUE(sNext < sEnd);
            int iOneLen = (int) (sEnd - sNext);
            TCharArray sTmp = TCharArray(sNext,iOneLen);
            bRet.append(TCseObj(CUT_FROM,sTmp));
        }
    }

    return TObjArray(CUT_FROM,bRet);
}

TObjArray TCharArray::split(const TXchar* sSep, int count) const
{
    return split(sSep,count,false);
}

TObjArray TCharArray::splitLines(TBool keepEnds, int count) const
{
    TObjArray bRet;
    if (count == 0) return bRet;
    TCharBuffLocker lock;

    int iLen = len();
    if (iLen == 0) return bRet;
    TXchar *sEnd  = m_data + iLen;

    // split with white space
    TXchar *sTarg = m_data;
    TXchar *sLast = m_data;
    TXchar ch;

    while ((ch = *sTarg) != 0)
    {
        sTarg++;
        if ( ch == _T('\r') || ch == _T('\n') )
        {   // current is white space
            int iExt = 1;
            int iOneLen = (int) (sTarg - sLast);
            if (ch == _T('\r') && *sTarg == _T('\n'))
            {
                sTarg++;
                iExt++;
                iOneLen++;
            }

            if (! keepEnds) iOneLen -= iExt;
            if (iOneLen == 0)
                bRet.append(CseEmptyStr);
            else
            {
                TCharArray sTmp = TCharArray(sLast,iOneLen);
                bRet.append(TCseObj(CUT_FROM,sTmp));
            }

            if (sTarg >= sEnd || (count > 0 && bRet.len() >= count))
            {
                sLast = NULL;
                break;
            }
            else sLast = sTarg;
        }
        
        if (sTarg == sEnd)
        {
            if (sLast >= sEnd)
                sLast = NULL;
            break;
        }
        else if (sTarg > sEnd)
        {
            sLast = NULL;
            break;
        }   
    }

    if (sLast != NULL)
    {
        int iOneLen = (int) (sEnd - sLast);
        if (iOneLen)
        {
            TCharArray sTmp = TCharArray(sLast,iOneLen);
            bRet.append(TCseObj(CUT_FROM,sTmp));
        }
    }

    return TObjArray(CUT_FROM,bRet);
}

STATIC TCharArray JoinTwoCharBuff(const TXchar *s1, int iLen1, const TXchar *s2, int iLen2)
{
    int iLen = iLen1 + iLen2;

    if (iLen == 0)
        return TCharArray();
    else
    {
        int iPad = (iLen + 1) / 2;
        TCharArray ret(s1,iLen1,iLen2+iPad);
        ret.insertSlice(iLen1,s2,iLen2);
        return TCharArray(CUT_FROM,ret);
    }
}

TCharArray TCharArray::operator+(const TCharArray& y) const
{
    TCharBuffLocker lock;
    return JoinTwoCharBuff(addr(),len(),y.addr(),y.len());
}

TCharArray TCharArray::operator+(const TXchar *y) const
{
    TCharBuffLocker lock;
    int iLen = (y == NULL)? 0: STRLEN(y);
    return JoinTwoCharBuff(addr(),len(),y,iLen);
}

TCharArray TCharArray::operator+(TXchar y) const
{
    TCharBuffLocker lock;
    return JoinTwoCharBuff(addr(),len(),&y,1);
}

TCharArray operator+(TXchar x, const TCharArray& y)
{
    TCharBuffLocker lock;
    return JoinTwoCharBuff(&x,1,y.addr(),y.len());
}

TCharArray operator+(const TXchar *x, const TCharArray& y)
{
    TCharBuffLocker lock;
    int iLen = (x == NULL)? 0: STRLEN(x);
    return JoinTwoCharBuff(x,iLen,y.addr(),y.len());
}

TBool TCharArray::operator==(const TCharArray& y) const
{
    TCharBuffLocker lock;
    return StrNCompare(addr(),len(),y.addr(),y.len()) == 0;
}

TBool TCharArray::operator==(const TXchar *y) const
{
    TCharBuffLocker lock;
    int iLen = (y == NULL)? 0: STRLEN(y);
    return StrNCompare(addr(),len(),y,iLen) == 0;
}

TBool operator==(const TXchar *x, const TCharArray& y)
{
    TCharBuffLocker lock;
    int iLen = (x == NULL)? 0: STRLEN(x);
    return StrNCompare(x,iLen,y.addr(),y.len()) == 0;
}

TBool TCharArray::operator!=(const TCharArray& y) const
{
    TCharBuffLocker lock;
    return StrNCompare(addr(),len(),y.addr(),y.len()) != 0;
}

TBool TCharArray::operator!=(const TXchar *y) const
{
    TCharBuffLocker lock;
    int iLen = (y == NULL)? 0: STRLEN(y);
    return StrNCompare(addr(),len(),y,iLen) != 0;
}

TBool operator!=(const TXchar *x, const TCharArray& y)
{
    TCharBuffLocker lock;
    int iLen = (x == NULL)? 0: STRLEN(x);
    return StrNCompare(x,iLen,y.addr(),y.len()) != 0;
}

TBool TCharArray::operator>(const TCharArray& y) const
{
    TCharBuffLocker lock;
    return StrNCompare(addr(),len(),y.addr(),y.len()) > 0;
}

TBool TCharArray::operator>(const TXchar *y) const
{
    TCharBuffLocker lock;
    int iLen = (y == NULL)? 0: STRLEN(y);
    return StrNCompare(addr(),len(),y,iLen) > 0;
}

TBool operator>(const TXchar *x, const TCharArray& y)
{
    TCharBuffLocker lock;
    int iLen = (x == NULL)? 0: STRLEN(x);
    return StrNCompare(x,iLen,y.addr(),y.len()) > 0;
}

TBool TCharArray::operator>=(const TCharArray& y) const
{
    TCharBuffLocker lock;
    return StrNCompare(addr(),len(),y.addr(),y.len()) >= 0;
}

TBool TCharArray::operator>=(const TXchar *y) const
{
    TCharBuffLocker lock;
    int iLen = (y == NULL)? 0: STRLEN(y);
    return StrNCompare(addr(),len(),y,iLen) >= 0;
}

TBool operator>=(const TXchar *x, const TCharArray& y)
{
    TCharBuffLocker lock;
    int iLen = (x == NULL)? 0: STRLEN(x);
    return StrNCompare(x,iLen,y.addr(),y.len()) >= 0;
}

TBool TCharArray::operator<(const TCharArray& y) const
{
    TCharBuffLocker lock;
    return StrNCompare(addr(),len(),y.addr(),y.len()) < 0;
}

TBool TCharArray::operator<(const TXchar *y) const
{
    TCharBuffLocker lock;
    int iLen = (y == NULL)? 0: STRLEN(y);
    return StrNCompare(addr(),len(),y,iLen) < 0;
}

TBool operator<(const TXchar *x, const TCharArray& y)
{
    TCharBuffLocker lock;
    int iLen = (x == NULL)? 0: STRLEN(x);
    return StrNCompare(x,iLen,y.addr(),y.len()) < 0;
}

TBool TCharArray::operator<=(const TCharArray& y) const
{
    TCharBuffLocker lock;
    return StrNCompare(addr(),len(),y.addr(),y.len()) <= 0;
}

TBool TCharArray::operator<=(const TXchar *y) const
{
    TCharBuffLocker lock;
    int iLen = (y == NULL)? 0: STRLEN(y);
    return StrNCompare(addr(),len(),y,iLen) <= 0;
}

TBool operator<=(const TXchar *x, const TCharArray& y)
{
    TCharBuffLocker lock;
    int iLen = (x == NULL)? 0: STRLEN(x);
    return StrNCompare(x,iLen,y.addr(),y.len()) <= 0;
}
